/**
 * Copyright (C), 2017-2018, XXX有限公司
 * FileName: Register
 * Author:   zengjian
 * Date:     2018/9/1 22:59
 * Description: 实例注册中心，用以存储扫描的实例
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package org.yinxue.swing.unit.context;

import org.yinxue.swing.unit.model.ClassDesc;
import org.yinxue.swing.unit.model.JavaFile;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 〈一句话功能简述〉<br>
 * 〈实例注册中心，用以存储扫描的实例〉
 *
 * @author zengjian
 * @create 2018/9/1
 * @since 1.0.0
 */
public class Register {

    /**
     * {javaFile:classDesc}
     */
    private static Map<JavaFile, ClassDesc> preparedCreateFilesMap = new ConcurrentHashMap<>(256);


    /**
     * {fullClassName:classDesc}
     */
    private static Map<String, ClassDesc> classDescMap = new ConcurrentHashMap<>(256);

    /**
     * {fullClassName:javaFile}
     */
    private static Map<String, JavaFile> javaFileMap = new ConcurrentHashMap<>(256);

    /**
     * 导入包正则匹配， 比如 util.* 等 的包，key为带*号正则式，value为 名称与导入名称的键值对
     */
    private static Map<String, Map<String, String>> importRegexMap = new ConcurrentHashMap<>();

    /**
     * {simpleName, importPath}
     */
    private static Map<String, String> commonImportMap = new ConcurrentHashMap<>();

    private static Class<?>[] commonClazz = new Class[]{
            Map.class, HashMap.class, TreeMap.class, LinkedHashMap.class,
            Set.class, HashSet.class, TreeSet.class, LinkedHashSet.class,
            Collection.class, List.class, ArrayList.class, LinkedList.class,
            BigInteger.class, BigDecimal.class, Timestamp.class, Properties.class};

    /**
     * 别名map, {simpleName, List:classNames}
     */
    private static Map<String, Set<String>> javaFileAliasMap = new ConcurrentHashMap<>(256);

    public boolean register(final JavaFile file) {
        final String className = file.classDesc.className;
        final String simpleName = file.classDesc.simpleName;
        // 存储file与classDesc的映射关系
        preparedCreateFilesMap.put(file, file.classDesc);
        // 存储全名与file的映射关系，与上关联
        javaFileMap.put(className, file);
        // 存储别名
        if (javaFileAliasMap.containsKey(simpleName)) {
            javaFileAliasMap.get(simpleName).add(className);
        } else {
            Set<String> set = new HashSet<>();
            set.add(className);
            javaFileAliasMap.put(simpleName, set);
        }
        // 存储各类导入包的的*映射关系
        final String importPath = file.classDesc.importPath;
        String importRegex = importPath.substring(0, importPath.lastIndexOf(".") + 1) + "*;";
        if (importRegexMap.containsKey(importRegex)) {
            importRegexMap.get(importRegex).put(simpleName, importPath);
        } else {
            Map<String, String> namePathMap = new TreeMap<>();
            namePathMap.put(simpleName, importPath);
            importRegexMap.put(importRegex, namePathMap);
        }
        return true;
    }

    public Map<String, String> getMatchRegetImportMap(String regexImportPath) {
        if (importRegexMap.containsKey(regexImportPath)) {
            return importRegexMap.get(regexImportPath);
        }
        return null;
    }

    public JavaFile getJavaFile(String className) {
        if (className.startsWith("com")) {
            return javaFileMap.get(className);
        }
        // className为简单名称，取匹配的第一个进行生成，后续可以改成匹配未生成单测文件的 HACK
        if (javaFileAliasMap.containsKey(className) && javaFileAliasMap.get(className) != null) {
            return javaFileMap.get(javaFileAliasMap.get(className).iterator().next());
        }
        return null;
    }

    public void register(ClassDesc classDesc) {
        if (classDesc.parent == null) {
            classDescMap.put(classDesc.className, classDesc);
        } else {
            // 只有包含内部类的情况下才会这样存储，#compositClassName 只在内部类有用
            if (classDesc.compositClassName != null) {
                classDescMap.put(classDesc.compositClassName, classDesc);
            }
        }
    }

    public ClassDesc getClassDesc(String className) {
        JavaFile javaFile = getJavaFile(className);
        if (javaFile != null) {
            return javaFile.classDesc;
        }
        return null;
    }

    public int classDescSize() {
        return classDescMap.size();
    }

    public int fileSize() {
        return preparedCreateFilesMap.size();
    }

    public Map<JavaFile, ClassDesc> getCreateFileMap() {
        return preparedCreateFilesMap;
    }

    public boolean isRegister() {
        return classDescMap.size() > 0;
    }

    public void stop() {
        preparedCreateFilesMap.clear();
        classDescMap.clear();
    }

    public String getCommonImportPath(String commonType) {
        if (commonImportMap.isEmpty()) {
            for (Class<?> clazz : commonClazz) {
                commonImportMap.put(clazz.getSimpleName(), "import "+clazz.getName()+";");
            }
        }
        return commonImportMap.get(commonType);
    }
}